﻿using Sgr.DataCategories.Stores;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.DataCategories.Services
{
    /// <summary>
    /// 默认的数据字典管理实现
    /// </summary>
    public class DefaultCategoryItemsManagement : ICategoryItemsManagement
    {
        private readonly IDataDictionaryStore _dictionaryStore;
        private readonly IEnumerable<IDataDictionaryProvider> _dataDictionaryProviders;
        private readonly IEnumerable<ICategoryTypeProvider> _categoryTypeProviders;
        private readonly Lazy<List<NameValue>> _allCategoryTypes;

        /// <summary>
        /// 初始化数据字典管理服务
        /// </summary>
        public DefaultCategoryItemsManagement(
            IDataDictionaryStore dictionaryStore,
            IEnumerable<IDataDictionaryProvider> dataDictionaryProviders,
            IEnumerable<ICategoryTypeProvider> categoryTypeProviders)
        {
            _dictionaryStore = dictionaryStore ?? throw new ArgumentNullException(nameof(dictionaryStore));
            _dataDictionaryProviders = dataDictionaryProviders ?? throw new ArgumentNullException(nameof(dataDictionaryProviders));
            _categoryTypeProviders = categoryTypeProviders ?? throw new ArgumentNullException(nameof(categoryTypeProviders));
            _allCategoryTypes = new Lazy<List<NameValue>>(InitializeCategoryTypes);
        }

        /// <summary>
        /// 异步刷新指定类别的数据字典缓存
        /// </summary>
        /// <param name="category">数据字典类别</param>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task RefreshCategoryAsync(string category, CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrWhiteSpace(category))
                throw new ArgumentException("类别名称不能为空", nameof(category));

            var items = await LoadCategoryItemsAsync(category, cancellationToken);

            //Console.WriteLine($"category = {category}, items count = {items.Count}");
            await _dictionaryStore.RefreshAsync(category, items, cancellationToken);
        }

        /// <summary>
        /// 异步刷新所有数据字典缓存
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task RefreshAllAsync(CancellationToken cancellationToken = default)
        {
            var categoryTypes = GetAllCategoryTypes();
            var tasks = categoryTypes.Select(ct => RefreshCategoryAsync(ct.Value, cancellationToken)).ToList();

            using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                cts.CancelAfter(TimeSpan.FromSeconds(60)); // 设置60秒超时
                try
                {
                    await Task.WhenAll(tasks);
                }
                catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
                {
                    System.Diagnostics.Debug.WriteLine("异步刷新所有数据字典缓存操作超时");
                }
            }
        }

        /// <summary>
        /// 异步预加载所有数据字典项
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        public async Task PreloadAllAsync(CancellationToken cancellationToken = default)
        {
            var categoryTypes = GetAllCategoryTypes();
            var tasks = categoryTypes.Select(ct => LoadCategoryItemsAsync(ct.Value, cancellationToken)).ToList();

            using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                cts.CancelAfter(TimeSpan.FromSeconds(60)); // 设置60秒超时
                try
                {
                    var results = await Task.WhenAll(tasks);

                    // 批量更新存储
                    foreach (var (items, category) in results.Zip(categoryTypes, (items, ct) => (items, ct.Value)))
                    {
                        await _dictionaryStore.RefreshAsync(category, items, cancellationToken);
                    }
                }
                catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
                {
                    System.Diagnostics.Debug.WriteLine("预加载操作超时");
                }
            }
        }

        #region 辅助方法

        /// <summary>
        /// 获取支持指定类别的数据字典提供者
        /// </summary>
        private IEnumerable<IDataDictionaryProvider> GetSupportedProviders(string category)
        {
            return _dataDictionaryProviders.Where(p => p.IsCategorySupported(category));
        }

        /// <summary>
        /// 异步加载指定类别的数据字典项
        /// </summary>
        private async Task<IReadOnlyDictionary<string, NameValue>> LoadCategoryItemsAsync(string category, CancellationToken cancellationToken)
        {
            var providers = GetSupportedProviders(category);
            if (!providers.Any())
            {
                return new Dictionary<string, NameValue>();
            }

            var allItems = new List<NameValue>();
            foreach (var provider in providers)
            {
                try
                {
                    var items = await provider.GetItemsAsync(category, cancellationToken).ConfigureAwait(false);
                    if (items != null && items.Any())
                    {
                        allItems.AddRange(items);
                    }
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine($"从提供者加载类别 {category} 时出错: {ex.Message}");
                }
            }

            // 合并并去重，使用最后一个同键的项
            var result = new Dictionary<string, NameValue>(allItems.Count);
            foreach (var group in allItems.GroupBy(i => i.Value))
            {
                result[group.Key] = group.Last();
            }
            return result;
        }

        /// <summary>
        /// 获取所有类别类型
        /// </summary>
        private List<NameValue> GetAllCategoryTypes()
        {
            return _allCategoryTypes.Value;
        }

        /// <summary>
        /// 初始化类别类型
        /// </summary>
        private List<NameValue> InitializeCategoryTypes()
        {
            var allCategoryTypes = new List<NameValue>();
            foreach (var provider in _categoryTypeProviders)
            {
                var categoryTypes = provider.GetCategoryTypes();
                if (categoryTypes != null && categoryTypes.Any())
                {
                    allCategoryTypes.AddRange(categoryTypes);
                }
            }
            return allCategoryTypes;
        }

        #endregion 辅助方法
    }
}